#pragma once
#include<sys/types.h>
#include<sys/socket.h>
#include<iostream>
#include<string>
#include<strings.h>
#include<cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>

#include"log.hpp"

// using func_t = std::function<std::string(const std::string&)>;

typedef std::function<std::string(const std::string&)> func_t;

//创建日志功能
Log lg;

//枚举常量
enum
{
    SOCKET_ERR=1,
    BIND_ERR
};

/// 初始化  缺省值
uint16_t defaultport = 8080;
std::string defaultip = "0.0.0.0";
const int size = 1024;

//udpserve
class UdpServe
{
public:
    //构造函数
    UdpServe(const uint16_t &port = defaultport, const std::string &ip = defaultip)
     :sockfd_(0)
     ,ip_(ip)
     ,port_(port)
     ,isrunning_(false)
    {
    }
     ~UdpServe()
    {
        if(sockfd_>0)
        //关闭
         close(sockfd_);
    }
    //创建套接字
    void Init()
    {
        //1.创建udp socket
        sockfd_=socket(AF_INET,SOCK_DGRAM,0);//PF_INET
        //网络文件描述符小于0，打印错误信息
        if(sockfd_<0)
        {
            //打印错误信息
            lg(Fatal,"socket create error,sockfd:%d",sockfd_);
            //以错误信息退出
            exit(SOCKET_ERR);
        }
        lg(Info,"socket creat  success, sockfd: %d",sockfd_);
        //2. bind socket 绑定套接字
        struct sockaddr_in local;
        //全部置为0；
        bzero(&local,sizeof(local));
        //协议家族
        local.sin_family=AF_INET;
        //端口号
        //需要保证我的端口号是网络字节序列，因为该端口号是要给对方发送的
        //将主机序列转化成网络字节序列，
        //如果是大端，不用管，如果是小端将小端序列转化成大端序列
        local.sin_port=htons(port_);

        //1. string -> uint32_t 2. uint32_t必须是网络序列的 // ??
        //inet_addr直接将字符串转化成网络序列
        local.sin_addr.s_addr=inet_addr(ip_.c_str());
        // local.sin_addr.s_addr = htonl(INADDR_ANY);
        //
        //绑定：
        //对local进行强转
        if(bind(sockfd_,(const struct sockaddr*)&local,sizeof(local))<0)
        {
            //绑定失败
            //打印错误信息
            lg(Fatal, "bind error, errno: %d, err string: %s", errno, strerror(errno));
            exit(BIND_ERR);
        }

        //方便进行查看：
        lg(Info,"bind success, errno: %d, err string: %s", errno, strerror(errno));
    }
    //将socket跑起来 运行
    void Run()
    //void Run(func_t func)
    {
        isrunning_ = true;
        //定义一个缓冲区
        char inbuffer[size];
        while(isrunning_)
        {
            //客户端结构体
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            ssize_t n = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&client, &len);
            if(n < 0)
            {
                //创建失败
                lg(Warning, "recvfrom error, errno: %d, err string: %s", errno, strerror(errno));
                continue;
            }
            //将信息读到后，当成字符串来看
            inbuffer[n] = 0;
            printf("client say: %s\n", inbuffer);
            //充当一次数据的处理
            std::string info = inbuffer;
            std::string echo_string="server echo# "+info;
            //std::string echo_string = func(info);
            //发送给对方
            sendto(sockfd_, echo_string.c_str(), echo_string.size(), 0, (const sockaddr*)&client, len);
        }
    }
   
private:
    int sockfd_; //网络文件描述符
    std::string ip_;//任意地址绑定
    uint16_t port_;//表明服务器进程的端口号
    bool isrunning_;//服务器的状态
};
